function PageProgress(user, sd, options) {
  this._user = user;
  this._sd = sd;
  this._options = (options) ? options : null;
  
  this._gui = { bride: { name: document.getElementById('input1'),
                         addrLn1: document.getElementById('input2'),
                         addrLn2: document.getElementById('input3'),
                         phone: document.getElementById('input4'),
                         mobile: document.getElementById('input5'),
                         email: document.getElementById('input6')
                       },
                source: document.getElementById('input7'),
                groom: { name: document.getElementById('input8'),
                         addrLn1: document.getElementById('input9'),
                         addrLn2: document.getElementById('input10'),
                         phone: document.getElementById('input11'),
                         mobile: document.getElementById('input12'),
                         email: document.getElementById('input13')
                       },
                price: { total: document.getElementById('input14'),
                         received: document.getElementById('input15'),
                         anticipated: document.getElementById('input16')
                       },
                orderTab: document.getElementById('td1'),
                order: { content: document.getElementById('td2'),
                       },
                note: document.getElementById('input25'),
                button: document.getElementById('button5')
              };
  
  this._popupBox = new PopupBox();
  
  this._createElements();
};

PageProgress.prototype._createElements = function() {
  this._loadData();
};

PageProgress.prototype._loadData = function() {
  this._customer = null;
  this._samples = null;
  this._packages = null;
  this._sources = null;
  this._retrieveCustomer();
  this._retrieveSamples();
  this._retrievePackages();
  this._retrieveSources();
};

PageProgress.prototype._verifyData = function() {
  if (this._customer && this._samples && this._packages && this._sources) {
    this._updateElements();
  }
};

PageProgress.prototype._retrieveCustomer = function() {
  var _self = this;
  if (this._options.cid) {
    new RequestUtils()._read('customer', null, 'd.oid = ' + this._options.cid, null, null, null, null, function(result, params) { _self._customer = (result.data.length == 1) ? result.data[0] : null;
                                                                                                                                  _self._verifyData.call(_self);
                                                                                                                                }, null);
  } else {
    this._customer = Customer.instance();
    this._customer.createdDate = this._sd;
    this._customer.sales = this._user;
    this._verifyData();
  }
};

PageProgress.prototype._retrieveSamples = function() {
  var _self = this;
  new RequestUtils()._read('sample', null, '', null, null, null, null, function(result, params) { _self._samples = result.data;
                                                                                                  _self._verifyData.call(_self);
                                                                                                }, null);
};

PageProgress.prototype._retrievePackages = function() {
  var _self = this;
  new RequestUtils()._read('package', null, null, null, null, null, null, function(result, params) { _self._packages = result.data;
                                                                                                     _self._verifyData.call(_self);
                                                                                                   }, null);
};

PageProgress.prototype._retrieveSources = function() {
  var _self = this;
  new RequestUtils()._read('source', null, null, null, null, null, null, function(result, params) { _self._sources = result.data;
                                                                                                    _self._verifyData.call(_self);
                                                                                                  }, null);
};

PageProgress.prototype._updateElements = function() {
  var _self = this;
  
  if (this._customer.orders.length == 0) {
    var order = MyOrder.instance();
    order.createdDate = this._sd;
    order.music.model = '{{$smarty.const.MODEL_NAME_MUSIC|escape:javascript}}';
    order.precon.model = '{{$smarty.const.MODEL_NAME_PRECON|escape:javascript}}';
    this._customer.orders[this._customer.orders.length] = order;
  }
  
  this._gui.bride.name.value = this._customer.bride.name;
  this._gui.bride.addrLn1.value = this._customer.bride.addrLn1;
  this._gui.bride.addrLn2.value = this._customer.bride.addrLn2;
  this._gui.bride.phone.value = this._customer.bride.phone;
  this._gui.bride.mobile.value = this._customer.bride.mobile;
  this._gui.bride.email.value = this._customer.bride.email;
  
  this._gui.groom.name.value = this._customer.groom.name;
  this._gui.groom.addrLn1.value = this._customer.groom.addrLn1;
  this._gui.groom.addrLn2.value = this._customer.groom.addrLn2;
  this._gui.groom.phone.value = this._customer.groom.phone;
  this._gui.groom.mobile.value = this._customer.groom.mobile;
  this._gui.groom.email.value = this._customer.groom.email;
  
  this._gui.bride.name.onchange = function() { _self._customer.bride.name = this.value; };
  this._gui.bride.addrLn1.onchange = function() { _self._customer.bride.addrLn1 = this.value; };
  this._gui.bride.addrLn2.onchange = function() { _self._customer.bride.addrLn2 = this.value; };
  this._gui.bride.phone.onchange = function() { _self._customer.bride.phone = this.value; };
  this._gui.bride.mobile.onchange = function() { _self._customer.bride.mobile = this.value; };
  this._gui.bride.email.onchange = function() { _self._customer.bride.email = this.value; };
  this._gui.groom.name.onchange = function() { _self._customer.groom.name = this.value; };
  this._gui.groom.addrLn1.onchange = function() { _self._customer.groom.addrLn1 = this.value; };
  this._gui.groom.addrLn2.onchange = function() { _self._customer.groom.addrLn2 = this.value; };
  this._gui.groom.phone.onchange = function() { _self._customer.groom.phone = this.value; };
  this._gui.groom.mobile.onchange = function() { _self._customer.groom.mobile = this.value; };
  this._gui.groom.email.onchange = function() { _self._customer.groom.email = this.value; };
  
  for (var i = 0, il = this._sources.length; i < il; i++) {
    var source = this._sources[i];
    var option = new Option(source.name);
    this._gui.source.options[this._gui.source.options.length] = option;
    if (option.text == this._customer.source){
      this._gui.source.selectedIndex = this._gui.source.options.length - 1;
    }
  }
  if (this._sources.length > 0) {
    this._customer.source = this._gui.source.options[this._gui.source.selectedIndex].text;
    this._gui.source.onchange = function() { _self._customer.source = this.options[this.selectedIndex].text; };
  }
  
  this._gui.note.value = this._customer.note;
  this._gui.note.onchange = function() { _self._customer.note = this.value; };
  
  this._updateOrders(0);
};

PageProgress.prototype._updateOrders = function(index) {
  var unique, td, _self = this;

  var total = 0;
  var received = 0;

  unique = MiscUtils.unique();
  new GTabOrders(unique, this._gui.orderTab, this._customer.orders, index);
  for (var i = 0, il = this._customer.orders.length; i < il; i++) {
    var order = this._customer.orders[i];
    
    total += parseFloat(order.price, 10);
    
    var td = document.getElementById(unique + '_' + i);
    td._index = i;
    td.onclick = function() { _self._updateOrders.call(_self, this._index); };
  }
  this._updateOrder(index);
  
  this._gui.price.total.value = total;
  this._gui.price.received.value = received;
  this._gui.price.anticipated.value = total - received;
};

PageProgress.prototype._updateOrder = function(index) {
  var unique, table, tr, td, order = this._customer.orders[index], _self = this;
  
  DOMUtils.removeChildElements(this._gui.order.content);
  
  table = document.createElement('table');
  this._gui.order.content.appendChild(table);
  
  tr = table.insertRow(-1);
  td = tr.insertCell(-1);
  td.appendChild(document.createTextNode('Video Music'));
  td = tr.insertCell(-1);
  new EditStatus(td, order.music, function() { _self._retrieveCustomer.call(_self); }, { order: order, now: this._sd, registrar: this._user, key: '{{$smarty.const.MODEL_NAME_MUSIC|escape:javascript}}' });

  tr = table.insertRow(-1);
  td = tr.insertCell(-1);
  td.appendChild(document.createTextNode('Pre wedding Consulation'));
  td = tr.insertCell(-1);
  new EditStatus(td, order.precon, function() { _self._retrieveCustomer.call(_self); }, { order: order, now: this._sd, registrar: this._user,  key: '{{$smarty.const.MODEL_NAME_PRECON|escape:javascript}}' });

  for (var i = 0, il = order.tasks.length; i < il; i++) {
    var task = order.tasks[i];
    tr = table.insertRow(-1);
    td = tr.insertCell(-1);
    td.appendChild(document.createTextNode(SimpleDate.format(task.date)));
    for (var i = 0, il = task.photographers.length; i < il; i++) {
      var photographer = task.photographers[i];
      tr = table.insertRow(-1);
      td = tr.insertCell(-1);
      td.appendChild(document.createTextNode((photographer.assignee) ? photographer.assignee.account : 'Photographer'));
      td = tr.insertCell(-1);
      new EditStatus(td, photographer.status, function() { _self._retrieveCustomer.call(_self); }, { order: order, now: this._sd, registrar: this._user,  key: '{{$smarty.const.MODEL_NAME_USER_PHOTOGRAPHER|escape:javascript}}' });
    }
    for (var i = 0, il = task.videographers.length; i < il; i++) {
      var videographer = task.videographers[i];
      tr = table.insertRow(-1);
      td = tr.insertCell(-1);
      td.appendChild(document.createTextNode((videographer.assignee) ? videographer.assignee.account : 'Videographer'));
      td = tr.insertCell(-1);
      new EditStatus(td, videographer.status, function() { _self._retrieveCustomer.call(_self); }, { order: order, now: this._sd, registrar: this._user,  key: '{{$smarty.const.MODEL_NAME_USER_VIDEOGRAPHER|escape:javascript}}' });
    }
    for (var i = 0, il = task.makeups.length; i < il; i++) {
      var makeup = task.makeups[i];
      tr = table.insertRow(-1);
      td = tr.insertCell(-1);
      td.appendChild(document.createTextNode((makeup.assignee) ? makeup.assignee.account : 'Makeup'));
      td = tr.insertCell(-1);
      new EditStatus(td, makeup.status, function() { _self._retrieveCustomer.call(_self); }, { order: order, now: this._sd, registrar: this._user,  key: '{{$smarty.const.MODEL_NAME_USER_MAKEUP|escape:javascript}}' });
    }
  }
  
  tr = table.insertRow(-1);
  td = tr.insertCell(-1);
  td.appendChild(document.createTextNode('Products'));
  for (var i = 0, il = order.produces.length; i < il; i++) {
    var produce = order.produces[i];
    tr = table.insertRow(-1);
    td = tr.insertCell(-1);
    td.appendChild(document.createTextNode(produce.quantity + ' x ' + produce.product.name + ((produce.assignee.userId) ? ' (' + produce.assignee.account + ')' : '')));
    td = tr.insertCell(-1);
    new EditStatus(td, produce.status, function() { _self._retrieveCustomer.call(_self); }, { order: order, now: this._sd, registrar: this._user,  key: produce.product.model });
  }
};